//
// * Copyright (c) 2002-2010 "Neo Technology,"
// *     Network Engine for Objects in Lund AB [http://neotechnology.com]
// *
// * This file is part of Neo4j.
// * 
// * Neo4j is free software: you can redistribute it and/or modify
// * it under the terms of the GNU Affero General Public License as
// * published by the Free Software Foundation, either version 3 of the
// * License, or (at your option) any later version.
// * 
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// * GNU Affero General Public License for more details.
// * 
// * You should have received a copy of the GNU Affero General Public License
// * along with this program. If not, see <http://www.gnu.org/licenses/>.
// 
using System.Collections.Generic;
namespace org.neo4j.graphdb
{
    ///
/// <summary> * A node in the graph with properties and relationships to other entities.
/// * Along with <seealso cref="Relationship relationships"/>, nodes are the core building
/// * blocks of the Neo4j data representation model. Nodes are created by invoking
/// * the <seealso cref="GraphDatabaseService#createNode"/> method.
/// * <p>
/// * Node has three major groups of operations: operations that deal with
/// * relationships, operations that deal with properties (see
/// * <seealso cref="PropertyContainer"/>) and operations that create {@link Traverser
/// * traversers}.
/// * <p>
/// * The relationship operations provide a number of overloaded accessors (such as
/// * <code>getRelationships(...)</code> with "filters" for type, direction, etc),
/// * as well as the factory method {@link #createRelationshipTo
/// * createRelationshipTo(...)} that connects two nodes with a relationship. It
/// * also includes the convenience method {@link #getSingleRelationship
/// * getSingleRelationship(...)} for accessing the commonly occurring
/// * one-to-zero-or-one association.
/// * <p>
/// * The property operations give access to the key-value property pairs. Property
/// * keys are always strings. Valid property value types are all the Java
/// * primitives (<code>int</code>, <code>byte</code>, <code>float</code>, etc),
/// * <code>java.lang.String</code>s and arrays of primitives and Strings.
/// * <p>
/// * <b>Please note</b> that Neo4j does NOT accept arbitrary objects as property
/// * values. <seealso cref="setProperty(string, object) setProperty()"/> takes a
/// * <code>java.lang.Object</code> only to avoid an explosion of overloaded
/// * <code>setProperty()</code> methods. For further documentation see
/// * <seealso cref="PropertyContainer"/>.
/// * <p>
/// * The traversal factory methods instantiate a <seealso cref="Traverser traverser"/> that
/// * starts traversing from this node.
/// * <p>
/// * A node's id is unique, but may not be unique over time since neo4j reuses
/// * deleted ids. See <a href="http://wiki.neo4j.org/content/Id_Reuse">
/// * wiki.neo4j.org/content/Id_Reuse</a>. </summary>
/// 
	public interface Node : PropertyContainer
	{
        ///    
        ///<summary> * Returns the unique id of this node. Ids are garbage collected over time
        /// so they are only guaranteed to be unique during a specific time span: if
        /// the node is deleted, it's likely that a new node at some point will get
        /// the old id. <b>Note</b>: this makes node ids brittle as public APIs.
        ///  </summary>
        /// <returns> the id of this node </returns>
        ///
		long GetId();
        ///    
        ///<summary> * Deletes this node if it has no relationships attached to it. If
        /// <code>delete()</code> is invoked on a node with relationships, an
        /// unchecked exception will be raised when the transaction is committed.
        /// Invoking any methods on this node after <code>delete()</code> has
        /// returned is invalid and will lead to unspecified behavior.
        ///  </summary>
        /// <exception cref="RuntimeException"> if this node has relationships attached to it </exception>
        ///
		void Delete();
	    // Relationships
        ///    
        ///<summary> * Returns all the relationships attached to this node. If no relationships
        /// are attached to this node, an empty iterable will be returned.
        ///  </summary>
        /// <returns> all relationships attached to this node </returns>
        ///
        IEnumerable<Relationship> GetRelationships();
        ///    
        ///<summary> * Returns <code>true</code> if there are any relationships attached to this
        /// node, <code>false</code> otherwise.
        ///  </summary>
        /// <returns> <code>true</code> if there are any relationships attached to this
        ///         node, <code>false</code> otherwise </returns>
        ///
		bool HasRelationship();
        ///    
        ///<summary> * Returns all the relationships of any of the types in <code>types</code>
        /// that are attached to this node, regardless of direction. If no
        /// relationships of the given types are attached to this node, an empty
        /// iterable will be returned.
        ///  </summary>
        /// <param name="types"> the given relationship type(s) </param>
        /// <returns> all relationships of the given type(s) that are attached to this
        ///         node </returns>
        ///
        IEnumerable<Relationship> GetRelationships(params RelationshipType[] types);
        ///    
        ///<summary> * Returns <code>true</code> if there are any relationships of any of the
        /// types in <code>types</code> attached to this node (regardless of
        /// direction), <code>false</code> otherwise.
        ///  </summary>
        /// <param name="types"> the given relationship type(s) </param>
        /// <returns> <code>true</code> if there are any relationships of any of the
        ///         types in <code>types</code> attached to this node,
        ///         <code>false</code> otherwise </returns>
        ///
		bool HasRelationship(params RelationshipType[] types);
        ///    
        ///<summary> * Returns all <seealso cref="Direction#OUTGOING OUTGOING"/> or
        /// <seealso cref="Direction#INCOMING INCOMING"/> relationships from this node. If
        /// there are no relationships with the given direction attached to this
        /// node, an empty iterable will be returned. If <seealso cref="Direction#BOTH BOTH"/>
        /// is passed in as a direction, relationships of both directions are
        /// returned (effectively turning this into <code>getRelationships()</code>).
        ///  </summary>
        /// <param name="dir"> the given direction, where <code>Direction.OUTGOING</code>
        ///            means all relationships that have this node as
        ///            <seealso cref="Relationship#getStartNode() start node"/> and <code>
        /// Direction.INCOMING</code>
        ///            means all relationships that have this node as
        ///            <seealso cref="Relationship#getEndNode() end node"/> </param>
        /// <returns> all relationships with the given direction that are attached to
        ///         this node </returns>
        ///
        IEnumerable<Relationship> GetRelationships(Direction dir);
        ///    
        ///<summary> * Returns <code>true</code> if there are any relationships in the given
        /// direction attached to this node, <code>false</code> otherwise. If
        /// <seealso cref="Direction#BOTH BOTH"/> is passed in as a direction, relationships of
        /// both directions are matched (effectively turning this into
        /// <code>hasRelationships()</code>).
        ///  </summary>
        /// <param name="dir"> the given direction, where <code>Direction.OUTGOING</code>
        ///            means all relationships that have this node as
        ///            <seealso cref="Relationship#getStartNode() start node"/> and <code>
        /// Direction.INCOMING</code>
        ///            means all relationships that have this node as
        ///            <seealso cref="Relationship#getEndNode() end node"/> </param>
        /// <returns> <code>true</code> if there are any relationships in the given
        ///         direction attached to this node, <code>false</code> otherwise </returns>
        ///
		bool HasRelationship(Direction dir);
        ///    
        ///<summary> * Returns all relationships with the given type and direction that are
        /// attached to this node. If there are no matching relationships, an empty
        /// iterable will be returned.
        ///  </summary>
        /// <param name="type"> the given type </param>
        /// <param name="dir"> the given direction, where <code>Direction.OUTGOING</code>
        ///            means all relationships that have this node as
        ///            <seealso cref="Relationship#getStartNode() start node"/> and <code>
        /// Direction.INCOMING</code>
        ///            means all relationships that have this node as
        ///            <seealso cref="Relationship#getEndNode() end node"/> </param>
        /// <returns> all relationships attached to this node that match the given type
        ///         and direction </returns>
        ///
        IEnumerable<Relationship> HetRelationships(RelationshipType type, Direction dir);
        ///    
        ///<summary> * Returns <code>true</code> if there are any relationships of the given
        /// relationship type and direction attached to this node, <code>false</code>
        /// otherwise.
        ///  </summary>
        /// <param name="type"> the given type </param>
        /// <param name="dir"> the given direction, where <code>Direction.OUTGOING</code>
        ///            means all relationships that have this node as
        ///            <seealso cref="Relationship#getStartNode() start node"/> and <code>
        /// Direction.INCOMING</code>
        ///            means all relationships that have this node as
        ///            <seealso cref="Relationship#getEndNode() end node"/> </param>
        /// <returns> <code>true</code> if there are any relationships of the given
        ///         relationship type and direction attached to this node,
        ///         <code>false</code> otherwise </returns>
        ///
		bool HasRelationship(RelationshipType type, Direction dir);
        ///    
        ///<summary> * Returns the only relationship of a given type and direction that is
        /// attached to this node, or <code>null</code>. This is a convenience method
        /// that is used in the commonly occuring situation where a node has exactly
        /// zero or one relationships of a given type and direction to another node.
        /// Typically this invariant is maintained by the rest of the code: if at any
        /// time more than one such relationships exist, it is a fatal error that
        /// should generate an unchecked exception. This method reflects that
        /// semantics and returns either:
        /// <p>
        /// <ol>
        /// <li><code>null</code> if there are zero relationships of the given type
        /// and direction,</li>
        /// <li>the relationship if there's exactly one, or
        /// <li>throws an unchecked exception in all other cases.</li>
        /// </ol>
        /// <p>
        /// This method should be used only in situations with an invariant as
        /// described above. In those situations, a "state-checking" method (e.g.
        /// <code>hasSingleRelationship(...)</code>) is not required, because this
        /// method behaves correctly "out of the box."
        ///  </summary>
        /// <param name="type"> the type of the wanted relationship </param>
        /// <param name="dir"> the direction of the wanted relationship (where
        ///            <code>Direction.OUTGOING</code> means a relationship that has
        ///            this node as <seealso cref="Relationship#getStartNode() start node"/>
        ///            and <code>
        /// Direction.INCOMING</code> means a relationship that has
        ///            this node as <seealso cref="Relationship#getEndNode() end node"/>) or
        ///            <seealso cref="Direction#BOTH"/> if direction is irrelevant </param>
        /// <returns> the single relationship matching the given type and direction if
        ///         exactly one such relationship exists, or <code>null</code> if
        ///         exactly zero such relationships exists </returns>
        /// <exception cref="RuntimeException"> if more than one relationship matches the given
        ///             type and direction </exception>
        ///
		Relationship GetSingleRelationship(RelationshipType type, Direction dir);
        ///    
        ///<summary> * Creates a relationship between this node and another node. The
        /// relationship is of type <code>type</code>. It starts at this node and
        /// ends at <code>otherNode</code>.
        /// <p>
        /// Neo4j doesn't support self-relationships, i.e. relationships where the
        /// start node and end node are the same. If <code>otherNode</code> is the
        /// same as this node then an exception will be thrown.
        /// <p>
        /// A relationship is equally well traversed in both directions so there's no
        /// need to create another relationship in the opposite direction (in regards
        /// to traversal or performance).
        ///  </summary>
        /// <param name="otherNode"> the end node of the new relationship </param>
        /// <param name="type"> the type of the new relationship </param>
        /// <returns> the newly created relationship </returns>
        ///
		Relationship CreateRelationshipTo(Node otherNode, RelationshipType type);
	    // Traversal
        ///    
        ///<summary> * Instantiates a traverser that will start at this node and traverse
        /// according to the given order and evaluators along the specified
        /// relationship type and direction. If the traverser should traverse more
        /// than one <code>RelationshipType</code>/<code>Direction</code> pair, use
        /// one of the overloaded variants of this method. The created traverser will
        /// iterate over each node that can be reached from this node by the spanning
        /// tree formed by the given relationship types (with direction) exactly
        /// once. For more information about traversal, see the <seealso cref="Traverser"/>
        /// documentation.
        ///  </summary>
        /// <param name="traversalOrder"> the traversal order </param>
        /// <param name="stopEvaluator"> an evaluator instructing the new traverser about
        ///            when to stop traversing, either a predefined evaluator such as
        ///            <seealso cref="StopEvaluator#END_OF_GRAPH"/> or a custom-written
        ///            evaluator </param>
        /// <param name="returnableEvaluator"> an evaluator instructing the new traverser
        ///            about whether a specific node should be returned from the
        ///            traversal, either a predefined evaluator such as
        ///            <seealso cref="ReturnableEvaluator#ALL"/> or a customer-written
        ///            evaluator </param>
        /// <param name="relationshipType"> the relationship type that the traverser will
        ///            traverse along </param>
        /// <param name="direction"> the direction in which the relationships of type
        ///            <code>relationshipType</code> will be traversed </param>
        /// <returns> a new traverser, configured as above </returns>
        ///
		Traverser Traverse(Order traversalOrder, StopEvaluator stopEvaluator, ReturnableEvaluator returnableEvaluator, RelationshipType relationshipType, Direction direction);
        ///    
        ///<summary> * Instantiates a traverser that will start at this node and traverse
        /// according to the given order and evaluators along the two specified
        /// relationship type and direction pairs. If the traverser should traverse
        /// more than two <code>RelationshipType</code>/<code>Direction</code> pairs,
        /// use the overloaded
        /// {@link #traverse(Traverser.Order, StopEvaluator, ReturnableEvaluator, Object...)
        /// varargs variant} of this method. The created traverser will iterate over
        /// each node that can be reached from this node by the spanning tree formed
        /// by the given relationship types (with direction) exactly once. For more
        /// information about traversal, see the <seealso cref="Traverser"/> documentation.
        ///  </summary>
        /// <param name="traversalOrder"> the traversal order </param>
        /// <param name="stopEvaluator"> an evaluator instructing the new traverser about
        ///            when to stop traversing, either a predefined evaluator such as
        ///            <seealso cref="StopEvaluator#END_OF_GRAPH"/> or a custom-written
        ///            evaluator </param>
        /// <param name="returnableEvaluator"> an evaluator instructing the new traverser
        ///            about whether a specific node should be returned from the
        ///            traversal, either a predefined evaluator such as
        ///            <seealso cref="ReturnableEvaluator#ALL"/> or a customer-written
        ///            evaluator </param>
        /// <param name="firstRelationshipType"> the first of the two relationship types that
        ///            the traverser will traverse along </param>
        /// <param name="firstDirection"> the direction in which the first relationship type
        ///            will be traversed </param>
        /// <param name="secondRelationshipType"> the second of the two relationship types
        ///            that the traverser will traverse along </param>
        /// <param name="secondDirection"> the direction that the second relationship type
        ///            will be traversed </param>
        /// <returns> a new traverser, configured as above </returns>
        ///
	    // TODO: document the importance of reltype/dir order
		Traverser Traverse(Order traversalOrder, StopEvaluator stopEvaluator, ReturnableEvaluator returnableEvaluator, RelationshipType firstRelationshipType, Direction firstDirection, RelationshipType secondRelationshipType, Direction secondDirection);
        ///    
        ///<summary> * Instantiates a traverser that will start at this node and traverse
        /// according to the given order and evaluators along the specified
        /// relationship type and direction pairs. Unlike the overloaded variants of
        /// this method, the relationship types and directions are passed in as a
        /// "varargs" variable-length argument which means that an arbitrary set of
        /// relationship type and direction pairs can be specified. The
        /// variable-length argument list should be every other relationship type and
        /// direction, starting with relationship type, e.g:
        /// <p>
        /// <code>node.traverse( BREADTH_FIRST, stopEval, returnableEval,
        /// MyRels.REL1, Direction.OUTGOING, MyRels.REL2, Direction.OUTGOING,
        /// MyRels.REL3, Direction.BOTH, MyRels.REL4, Direction.INCOMING );</code>
        /// <p>
        /// Unfortunately, the compiler cannot enforce this so an unchecked exception
        /// is raised if the variable-length argument has a different constitution.
        /// <p>
        /// The created traverser will iterate over each node that can be reached
        /// from this node by the spanning tree formed by the given relationship
        /// types (with direction) exactly once. For more information about
        /// traversal, see the <seealso cref="Traverser"/> documentation.
        ///  </summary>
        /// <param name="traversalOrder"> the traversal order </param>
        /// <param name="stopEvaluator"> an evaluator instructing the new traverser about
        ///            when to stop traversing, either a predefined evaluator such as
        ///            <seealso cref="StopEvaluator#END_OF_GRAPH"/> or a custom-written
        ///            evaluator </param>
        /// <param name="returnableEvaluator"> an evaluator instructing the new traverser
        ///            about whether a specific node should be returned from the
        ///            traversal, either a predefined evaluator such as
        ///            <seealso cref="ReturnableEvaluator#ALL"/> or a customer-written
        ///            evaluator </param>
        /// <param name="relationshipTypesAndDirections"> a variable-length list of
        ///            relationship types and their directions, where the first
        ///            argument is a relationship type, the second argument the first
        ///            type's direction, the third a relationship type, the fourth
        ///            its direction, etc </param>
        /// <returns> a new traverser, configured as above </returns>
        /// <exception cref="RuntimeException"> if the variable-length relationship type /
        ///             direction list is not as described above </exception>
        ///
		Traverser Traverse(Order traversalOrder, StopEvaluator stopEvaluator, ReturnableEvaluator returnableEvaluator, params object[] relationshipTypesAndDirections);
	}
}